home *** CD-ROM | disk | FTP | other *** search
- /*
- File: Install.c
-
-
-
-
-
- Unfortunately, no matter how long awaited, it's still not done. In fact, this
- isn't even a release- this is just an image of the code taken in the middle of
- development.
-
- THIS CODE DOES NOT WORK AS A WHOLE. MUCH OF IT IS BUGGY AND / OR INCOMPLETE.
- YOU WOULD HAVE TO BE ABSOLUTELY INSANE TO USE ANY OF THIS CODE IN YOUR
- PROJECT WITHOUT EXTENSIVE THOUGHT, DEBUGGING AND TESTING.
-
-
-
-
-
-
- Contains: SCSI driver installation code
-
- Written by: Craig Prouse
-
- Copyright: © 1991-1992 by Apple Computer, Inc., all rights reserved.
-
- Change History (most recent first):
- <7> 4/24/92 tmd Changes based on new TDriveVars structure
- <6> 4/22/92 khs Fixes based on the code review, removed old partition map code
- (not really needed anymore)
-
- <5> 3/6/92 chp Fix a bug in ValidOldPartition where pdFSID was being tested for
- nonzero rather than zero.
- <4> 11/26/91 chp fix bugs: look for an open unit to install into rather than an
- occupied unit (logic was reversed), and set the correct bit in
- the dCtlFlags word to get an accRun call (was setting the
- correct bit in the wrong byte)
- <3> 11/25/91 chp rewrite InstallProc from scratch and add numerous supporting
- subroutines and data structures
- <2> 10/17/91 chp modify so that project builds correctly and add debug code
- <1> 10/17/91 chp first checked in
-
- To Do:
- */
-
- #define __FILE_NUMBER__ 0x3000
-
- #include <Types.h>
- #include <Traps.h>
- #include <Memory.h>
- #include <SysEqu.h>
- #include <Devices.h>
- #include <SCSI.h>
- #include <string.h>
- #include <PLStringFuncs.h>
- #include "DTS_SCSI_Driver.h"
- #include "DTS_SCSI_Debug.h"
-
-
- #define HiByte(a) (*(char *) &(a))
-
-
- // bits in dCtlFlags
- enum {
- dOpened = 5,
- dRAMBased,
- drvrActive
- };
-
- // base for SCSI device unit numbers; unit number = base + SCSI ID
- #define kSCSIUnitBase 32
-
- struct DriverHeader {
- short drvrFlags;
- short drvrDelay;
- short drvrEMask;
- short drvrMenu;
- short drvrOpen;
- short drvrPrime;
- short drvrCtl;
- short drvrStatus;
- short drvrClose;
- Str255 drvrName;
- };
- typedef struct DriverHeader DriverHeader;
-
- // DrvrHdr is an imported assembly language label for the driver's header
- extern DriverHeader DrvrHdr;
-
- extern Boolean BlindIsSafe (void);
- extern Boolean IsBootTime (void);
-
- static void SetPartition (TDriveVars *vars, Partition *partitionMap);
- static void InitPartitionVars (TDriveVars *vars, long partitionOffset, long partitionSize);
- static void RemoveDupDriver(short sourceUnit);
- static void ReplaceDriver(DCtlPtr dce,DriverHeader *newDriver);
- static Boolean ValidPartitionMap (Partition *pm);
- static Boolean HFSPartition (Partition *pm);
-
- #pragma parameter __D0 DriverInstall (__A0, __D0)
- static OSErr DriverInstall (Ptr drvrPtr, short refNum) = {_DrvrInstall};
-
- #pragma parameter __D0 DriverRemove (__D0)
- static OSErr DriverRemove (short refNum) = {_DrvrRemove};
-
- void InstallProc (Partition *partitionMap, short scsiID, Ptr sbData) {
- #pragma unused (sbData)
-
- DCtlPtr dce;
- DriverHeader *pDriver;
- TDriveVars *vars;
- short unit, refNum, ignoreRefNum;
- OSErr instErr;
-
- unit = kSCSIUnitBase + scsiID;
- refNum = ~unit;
- pDriver = &DrvrHdr;
-
- if (GetDCtlEntry(refNum) == nil) {
-
- //
- // _DrvrInstall allocates a DCtlHandle, places it in the unit table, and
- // stores the indicated refNum in the dCtlRefNum field. That's all it does.
- //
- instErr = DriverInstall((Ptr) pDriver, refNum);
-
- if (instErr == noErr) {
- // copy driver's header information into the DCE
-
- // *** Why don't we use GetDCtlEntry here ?
- dce = *(*(DCtlHandle **) UTableBase)[unit];
- dce->dCtlDriver = (Ptr) pDriver;
- dce->dCtlFlags = pDriver->drvrFlags & ~(1 << dRAMBased);
- dce->dCtlDelay = pDriver->drvrDelay;
- dce->dCtlEMask = pDriver->drvrEMask;
- dce->dCtlMenu = pDriver->drvrMenu;
-
- // driver is all installed, so now open it
- instErr = OpenDriver(pDriver->drvrName, &ignoreRefNum);
- if (instErr == noErr) {
- vars = *(TDriveVars **) dce->dCtlStorage;
- vars->driveID = scsiID; // save the drive's SCSI bus ID
- vars->driveBlockSize = 512; // this is an assumption
- vars->blindOK = BlindIsSafe();
-
- SetPartition(vars, partitionMap);
-
- //
- // There are a couple of details to attend to at boot time.
- //
- // - make sure we get an accRun callback
- // - defer enabling blind reads where appropriate
- //
- // At the callback, a disk insertion event will be posted if necessary
- // and we will reconsider whether to enable blind transfers if we don't
- // choose to enable them at this time.
- //
- if (IsBootTime()) {
- dce->dCtlFlags |= (dNeedTime << 8); // Change the high byte
- dce->dCtlDelay = 0; // right away
-
- // assume the file system doesn't see us until it proves otherwise
- vars->tickleFlag = true;
- }
-
- // remove duplicate copies of our driver
- RemoveDupDriver(unit);
-
- }
- else {
- DriverRemove(refNum);
-
- //
- // The SCSI Development Package 1.0 (dated 1986) here calls DisposPtr
- // on the pointer containing the disk driver code. While this has
- // worked, there could be problems related to this call. It is probably better to
- // just leave the driver's rotting corpse in the system heap. Note that this
- // case will only happen the first time we install the driver.
- //
-
- }
- }
- }
- }
-
-
- //
- // Remove duplicate copies of the driver. This routine searches through the
- // unit table for device entries which have the same driver name and version
- // as our driver and removes them, replacing them with references to our
- // driver. We only replace exact copies of our driver, because we can't
- // be certain we'll be compatible otherwise.
- //
- // Doing this saves us memory at runtime but it means we can't use code-
- // relative storage for static storage, since a driver may be shared
- // among several drives.
- //
- // The passed unit number indicates which driver to compare the others
- // to and to replace them with, and should be the unit number of the
- // driver we are currently installing.
- //
-
- static void RemoveDupDriver(short sourceUnit)
- { DCtlHandle *unitTable,dceH;
- DCtlPtr dce;
- short unit;
- unsigned char *version;
- DriverHeader *driver,*sourceDriver;
-
- unitTable = *(DCtlHandle **)UTableBase;
-
- // Loop through valid SCSI device driver unit numbers
-
- sourceDriver = (DriverHeader*) (*(unitTable[sourceUnit]))->dCtlDriver;
-
- for (unit = kSCSIUnitBase + 1;unit < kSCSIUnitBase + 7;unit++)
- { if (unit != sourceUnit)
- { dceH = unitTable[unit];
-
- if (dceH)
- { dce = *dceH;
- // Our driver is always referred to by a pointer
- if (dce && !(dce->dCtlFlags & (1 << dRAMBased)))
- { driver = (DriverHeader*)dce->dCtlDriver;
- if (PLstrcmp(driver->drvrName,kDriverName) == 0) // Does the name match?
- { // The version number byte is packed in immediately after the name
- version = driver->drvrName; // Point at the name
- version += *version + 1; // Advance by length + 1
- if (*version == kCurrentDriverVersion) // Does the version match?
- // Everything matches, so replace the driver with ourselves
- ReplaceDriver(dce,sourceDriver);
- }
- }
- }
- }
- }
- }
-
-
- //
- // Replace the driver referred to in a DCE with another driver. This assumes
- // that the DCE has a driver which conforms to our standard of having a long
- // just before the driver header which tells how many bytes into the driver's
- // memory manager block the driver header is; this allows us to back up to
- // find the start of the block so we can dispose of it. We also replace the
- // driver reference in the DCE with the new driver.
- //
-
- static void ReplaceDriver(DCtlPtr dce,DriverHeader *newDriver)
- { long offset;
- Ptr driverBlock;
- DriverHeader *oldDriver;
-
- oldDriver = (DriverHeader*) dce->dCtlDriver;
-
- // Replace the old driver reference with a pointer to the new driver; doing
- // this first makes the driver always valid (rather than disposing, then
- // replacing), plus it makes sure that we can't move the DCtlEntry, which
- // we might have an unstable pointer to, should DisposPtr ever start to
- // move memory.
-
- dce->dCtlDriver = (Ptr)newDriver;
-
- offset = *(((long*)oldDriver) - 1); // Offset is one long back from driver
- driverBlock = ((Ptr)oldDriver) - offset; // Back up to start of block
-
- // Now that we've got the start of the block, we need to deallocate the pointer
- // block. Theoretically, the driver could have been allocated in a locked
- // handle, but we're now requiring that anyone who loads arbitrary drivers
- // load them into a pointer block in the System heap. Thus, we assume that
- // we've now got a pointer to a Ptr block, and we'll just dispose of it.
-
- DisposPtr(driverBlock); // Dispose of old driver block
- }
-
-
- static void SetPartition (TDriveVars *vars, Partition *partitionMap) {
- //
- // Search the available partition map for an HFS partition. Only the new (IMV5)
- // partition map format are supported. If no partition map is found, no operation
- // is performed. The result is that the partition offset and size are left set
- // to zero in the drive variables and drive queue. This effectively disables the
- // driver from performing reads or writes since these are restricted to a valid
- // partition.
- //
- if (partitionMap != nil) {
- if (ValidPartitionMap(partitionMap)) {
- //
- // This is the partition map format documented in Inside Macintosh,
- // Volume V. This is the preferred implementation, and the one for
- // which interfaces are predefined.
- //
- while (ValidPartitionMap(partitionMap) && !HFSPartition(partitionMap)) {
- // scan partition map entries for one with an HFS file system ID
- partitionMap++;
- }
- if (ValidPartitionMap(partitionMap)) {
- // found an HFS partition: fill in drive variables
- InitPartitionVars(vars, partitionMap->pmPyPartStart, partitionMap->pmPartBlkCnt);
- }
- }
- }
- }
-
-
- static void InitPartitionVars (TDriveVars *vars, long partitionOffset, long partitionSize) {
- vars->partitionOffset = partitionOffset;
-
- // finish initializing the drive queue element
- vars->driveQElem.elem.dQDrvSz = partitionSize; // low word
- vars->driveQElem.elem.dQDrvSz2 = partitionSize >> 16; // high word
- }
-
-
- static Boolean ValidPartitionMap (Partition *pm) {
- //
- // This is a very simple routine but it is called from several places.
- // It's broken out separately for ease of maintenance.
- //
- return pm->pmSig == pMapSIG;
- }
-
-
- static Boolean HFSPartition (Partition *pm) {
- const char *hfsID = "Apple_HFS";
- const size_t kPartTypeSize = 32;
-
- return strncmp(pm->pmParType, hfsID, kPartTypeSize) == 0;
- }
-
-